﻿/*
 * zproc.cxx
 *
 *  Created on: 2014年10月4日
 *      Author: Fifi Lyu
 */

#include "zpsoe/zproc.h"
#include "zpsoe/zfilesys.h"
#include "zpsoe/zexception.h"
#include "zpsoe/zalgorithm/zstring.h"
#include "zpsoe/zalgorithm/zpath.h"
#ifdef PLATFORM_WIN32
    #include <comdef.h>
#else
    #include <errno.h>
    #include <linux/limits.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <unistd.h>
#endif
#include <cstdlib>

namespace zpsoe {

namespace zproc {
ZPSOE_SHARED_LIB_API bool current_work_dir(string &buf) {
    buf.clear();

#ifdef PLATFORM_WIN32
    TCHAR t_buf[MAX_PATH];
    LPTSTR lpt_str = t_buf;

    if (GetCurrentDirectory(MAX_PATH, lpt_str))
        buf = string(lpt_str);
#else
    char *ptr = get_current_dir_name();

    if (ptr != NULL) {
        buf = string(ptr);
        free(ptr);
    }
#endif
    return (buf.size() != 0);
}

ZPSOE_SHARED_LIB_API bool current_exe_path(string &buf) {
    buf.clear();
#ifdef PLATFORM_WIN32

    TCHAR sz_path_[MAX_PATH];

    if (GetModuleFileName(NULL, sz_path_, MAX_PATH))
    buf = string(sz_path_);
#else
    char buf_[PATH_MAX];
    ssize_t size_ = readlink("/proc/self/exe", buf_, PATH_MAX - 1);

    if (size_ != -1) {
        buf_[size_] = '\0';
        buf = string(buf_);
    }
#endif
    return (buf.size() != 0);
}

ZPSOE_SHARED_LIB_API bool current_exe_dir(string &buf) {
    using zalgorithm::zpath::dir_name;

    if (current_exe_path(buf)) {
        buf = dir_name(buf);
        return true;
    }

    return false;
}

#ifdef PLATFORM_WIN32
ZPSOE_SHARED_LIB_API bool lock_proc(const string &proc) {
    HANDLE hMutex = CreateMutex(NULL, false, proc.c_str());

    return !(GetLastError() == ERROR_ALREADY_EXISTS);
}

ZPSOE_SHARED_LIB_API bool unlock_proc(const string &proc) {
    HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, false, proc.c_str());

    if (hMutex == NULL) return false;

    CloseHandle(hMutex);
    return true;
}
#else
ZPSOE_SHARED_LIB_API bool lock_proc(
        const string &proc, const pid_t pid, const string &prefix) {
    using zalgorithm::zstring::to_str;

    const string pid_file_(prefix + "/" + proc + ".pid");

    // 进程存在
    if (zfilesys::is_exist(pid_file_)) {
        const string pid_(zfilesys::read_file(pid_file_));

        if (zfilesys::is_exist("/proc/" + pid_))
            return false;
    }

    try {
        zfilesys::write_file(pid_file_, to_str(pid));
    } catch (ZpsoeException &e) {
        return false;
    }

    return true;
}

ZPSOE_SHARED_LIB_API bool unlock_proc(
        const string &proc, const string &prefix) {
    const string pid_file_(prefix + "/" + proc + ".pid");

    if(zfilesys::is_exist(pid_file_))
        return zfilesys::delete_file(pid_file_);

    return false;
}

ZPSOE_SHARED_LIB_API void creat_daemon(const string &name, const bool to_null) {
    if (name.empty())
        ThrowZpsoeException("Daemon name is empty.");

    if (!zproc::lock_proc(name, getpid()))
        ThrowZpsoeException("Another instance of " + name + " is already running");

    const int noclose_(to_null ? 0 : 1);

    if (daemon(0, noclose_) != 0) {
        unlock_proc(name);
        ThrowZpsoeException(
                "Cannot run " + name + " in the background as system daemons.");
    }
}
#endif

} /* namespace zproc */

} /* namespace zpsoe */
